Insights - Tabela de Dados da Aeronaútica
Introdução
A ideia desse documento é pegar um dataset com qual não tenho familiaridade e tentar extrair algum tipo de insight ou algum fato interessante usando R, usando especialmente data.table, Rmarkdown para compilar um documento de como fui me mergulhando nos dados junto com alguns htmlwidgets no caminho, e possivelmente criar um demo de um aplicativo shiny no final.
Nesse caso, escolhi um dataset que me interessou sobre Ocorrências Aeronáuticas na Aviação Civil Brasileira. Imagino que terá como mexer um pouco com mapas usando Leatlet ou alguma outra direção que quisermos tomar.
Esses datasets são extraídos da CENIPA e estão disponíveis no site de dados abertos do Governo Federal.
Segue uma breve descrição do que está no site:
A base de dados de ocorrências aeronáuticas é gerenciada pelo Centro de Investigação e Prevenção de Acidentes Aeronáuticos (CENIPA). Constam nesta base de dados as ocorrências aeronáuticas notificadas ao CENIPA nos últimos 10 anos e que ocorreram em solo brasileiro.
Dentre as informações disponíveis estão os dados sobre as aeronaves envolvidas, fatalidades, local, data, horário dos eventos e informações taxonômicas típicas das investigações de acidentes (AIG). São resguardadas a privacidade de pessoas físicas/jurídicas envolvidas conforme previsto pela Lei de Acesso à Informação (Lei n° 12.527, de 18 de novembro de 2011).
- Informações dos dados utilizados nesse relatório:
| Campo | Valor |
|---|---|
| Fonte | http://www.fab.mil.br/cenipa/ |
| Autor | Centro de Investigação e Prevenção de Acidentes Aeronáuticos |
| Mantenedor | Centro de Investigação e Prevenção de Acidentes Aeronáuticos |
| Versão | 1.3 |
| Última Atualização | 5 de Outubro de 2021, 19:19 (UTC-03:00) |
| Criado | 1 de Junho de 2015, 15:37 (UTC-03:00) |
| Cobertura geográfica | Brasil |
| Cobertura temporal | 2010 a 2019 |
| Fale Conosco | estatistica.cenipa@fab.mil.br |
| Frequência de atualização | Anual |
| Granularidade geográfica | Aeródromo |
| Granularidade temporal | Hora:Minuto |
| VCGE | Aeronáutica [http://vocab.e.gov.br/2011/03/vcge#aeronautica], Transporte Aéreo [http://vocab.e.gov.br/2011/03/vcge#transporte-aereo] |
Importação e Tratamentos Iniciais dos Dados
Importação dos Dados
Bom, iniciei o programa importando as informações do portal da CENIPA (Centro de Investigação e Prevenção de Acidentes Aeronáuticos) encontrados no link mencionados na Introdução.
Note que se importarmos o programa sem especificar o encoding como “UTF-8”, então caracteres especiais do Português Brasil serão lidos incorretamente. e.g. “ã”, “é”, “Ç”, etc.
Cruzamento dos Dados
Explicação
Normalmente, essa seria um bom momento de dar uma olhada em algumas colunas e ver o que podemos fazer com elas. No entanto, lendo as informações no site de dados do Governo Federal, notei que apesar de termos 5 tabelas diferentes, há uma tabela “central” que possui informações adicionais distribuídas nas outras 4, assim como na imagem a seguir:
Como as tabelas são bem pequenas, com menos 10 mil linhas e 30 colunas, cruzá-las e trazer todas as informações em um único dataset poderá facilitar o tratamento de dados mais para frente. Talvez fique um pouco mais difícil de ter uma panorama geral só batendo o olho, mas dado o número colunas parece ser algo tolerável.
Como estou usando o pacote data.table, utilizarei-o para cruzar as informações baseado na chave seguindo a imagem do relacionamento de dados das tabelas acima. Extraindo as informações da imagem acima, seria algo assim:
Cruzamento
Achados sobre a chave
Primeira coisa, dei um head para ter um panorama geral da tabela central, ocorrencia - especialmente das chaves. Nunca se sabe se algo deu errado.
head(ocorrencia[, c("codigo_ocorrencia", "codigo_ocorrencia1", "codigo_ocorrencia2", "codigo_ocorrencia3", "codigo_ocorrencia4")])## codigo_ocorrencia codigo_ocorrencia1 codigo_ocorrencia2 codigo_ocorrencia3 codigo_ocorrencia4
## 1: 52242 52242 52242 52242 52242
## 2: 45331 45331 45331 45331 45331
## 3: 45333 45333 45333 45333 45333
## 4: 45401 45401 45401 45401 45401
## 5: 45407 45407 45407 45407 45407
## 6: 52243 52243 52243 52243 52243
Opa! Olhando o header, parece que ocorreu algo peculiar. As 5 primeiras linhas das 5 chaves possuem o valor idêntico!
Note que isso não significa que todas as linhas serão iguais. Porém, há uma leve suspeita para saber se isso é muito mais que uma mera coincidência, ou seja, que realmente esteja assim na tabela inteira.
Para checarmos no R se as colunas possuem valores iguais, podemos usar a função identical para saber se os elementos são iguais.
identical(
ocorrencia[, codigo_ocorrencia],
ocorrencia[, codigo_ocorrencia1],
ocorrencia[, codigo_ocorrencia2],
ocorrencia[, codigo_ocorrencia3],
ocorrencia[, codigo_ocorrencia4]
)## [1] TRUE
E olha só! As colunas são de fato idênticas! Pode ser que um dia essas colunas sejam diferentes por algum motivo no site, mas no momento de nossa análise elas são idênticas.
Isso não mudará muita coisa no nosso cruzamento, mas isso significa que podemos descartar alguns dados mais para frente após o cruzamento.
Cruzando as tabelas
Voltando ao que interessa, vamos para o cruzamento. Tentarei fazer 4 left joins seguidos trazendo as informações das 4 tabelas complementares para a tabela central, ocorrencia:
cruzamento1 <- ocorrencia[ocorrencia_tipo, on = "codigo_ocorrencia1"] # Left Join 1
cruzamento2 <- cruzamento1[aeronave, on = "codigo_ocorrencia2"] # Left Join 2
cruzamento3 <- cruzamento2[fator_contribuinte, on = "codigo_ocorrencia3"] # Left Join 3
# tabela <- cruzamento3[recomendacao, on = "codigo_ocorrencia4"] # Left Join 4Rodando o código acima sem a última linha estar comentada, obtive um erro vindo do último cruzamento, um left join entre ocorrencia e recomendacao:
Error in vecseq(f__, len, if (allow.cartesian || notjoin || !anyDuplicated(f, : Join results in 11387 rows; more than 6687 = nrow(x)+nrow(i). Check for duplicate key values in i each of which join to the same group in x over and over again. If that’s ok, try by=.EACHI to run j for each group to avoid the large allocation. If you are sure you wish to proceed, rerun with allow.cartesian=TRUE. Otherwise, please search for this error message in the FAQ, Wiki, Stack Overflow and data.table issue tracker for advice.
Será que são chaves mesmo?
Aparentemente as chaves de alguma das duas tabelas não são únicas. Vamos dar uma olhadinha na frequências das chaves (código de ocorrência - codigo_ocorrencia) das tabelas:
head(ocorrencia[, .(n = .N), by = codigo_ocorrencia][n > 1][order(-n)])## Empty data.table (0 rows and 2 cols): codigo_ocorrencia,n
head(ocorrencia_tipo[, .(n = .N), by = codigo_ocorrencia1][n > 1][order(-n)])## codigo_ocorrencia1 n
## 1: 66444 3
## 2: 78780 3
## 3: 78879 3
## 4: 78904 3
## 5: 79620 3
## 6: 79651 3
head(aeronave[, .(n = .N), by = codigo_ocorrencia2][n > 1][order(-n)])## codigo_ocorrencia2 n
## 1: 45689 3
## 2: 78249 3
## 3: 79441 3
## 4: 45903 2
## 5: 46255 2
## 6: 47245 2
head(fator_contribuinte[, .(n = .N), by = codigo_ocorrencia3][n > 1][order(-n)])## codigo_ocorrencia3 n
## 1: 53340 17
## 2: 52265 16
## 3: 45331 15
## 4: 53358 15
## 5: 53488 15
## 6: 45820 14
head(recomendacao[, .(n = .N), by = codigo_ocorrencia4][n > 1][order(-n)])## codigo_ocorrencia4 n
## 1: 52265 13
## 2: 66432 12
## 3: 47938 11
## 4: 45571 9
## 5: 46583 9
## 6: 77678 9
Bom, dado que não há uma chave comum entre as tabelas que não estejam duplicadas, não é possível fazer um join simples entre elas como eu gostaria de ter feito. No entanto, como as tabelas não possuem nenhum campo de valor que poderíamos agregar (exceto 3 colunas que contém o nome “total” de frequência, mas que podem ser recalculadas usando as variáveis de origem), é possível fazer algo ainda que nos ajude a colocar tudo numa tabela só, usando cruzamento cartesiano (cartesian join).
Cruzamento Cartesiano
Fazer isso fará com que a tabela após os cruzamentos deixe de ter uma única chave, mas dado que irei sumarizar ela posteriormente com apenas uma seleção das colunas, deve dar tudo certo.
Então, para fazer o cruzamento cartesiano no data.table basta especificar o argumento no final. Vamos ver se agora dará certo…
cruzamento1 <- ocorrencia_tipo[ocorrencia, on = "codigo_ocorrencia1", allow.cartesian = TRUE] # Left Join 1
cruzamento2 <- aeronave[cruzamento1, on = "codigo_ocorrencia2", allow.cartesian = TRUE] # Left Join 2
cruzamento3 <- fator_contribuinte[cruzamento2, on = "codigo_ocorrencia3", allow.cartesian = TRUE] # Left Join 3
tabela <- recomendacao[cruzamento3, on = "codigo_ocorrencia4", allow.cartesian = TRUE] # Left Join 4
head(tabela)## codigo_ocorrencia4 recomendacao_numero recomendacao_dia_assinatura recomendacao_dia_encaminhamento recomendacao_dia_feedback recomendacao_conteudo recomendacao_status recomendacao_destinatario_sigla recomendacao_destinatario codigo_ocorrencia3 fator_nome fator_aspecto fator_condicionante fator_area codigo_ocorrencia2 aeronave_matricula aeronave_operador_categoria aeronave_tipo_veiculo aeronave_fabricante aeronave_modelo aeronave_tipo_icao aeronave_motor_tipo aeronave_motor_quantidade
## 1: 52242 <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> 52242 <NA> <NA> <NA> <NA> 52242 PRCDL PARTICULAR AVIÃO RAYTHEON AIRCRAFT 58 BE58 PISTÃO BIMOTOR
## 2: 45331 A-582/CENIPA/2014 - 01 2016-07-29 2016-08-25 2016-12-20 Atuar junto às empresas que operam segundo o RBAC 121 de forma tal que assegure que o treinamento de Corporate Ressource Management (CRM) esteja adequado a realidade daquela empresa, que seja constantemente avaliado e reforçado (com a participação da alta direção), envolva todos os profissionais da instituição, que garanta a integração dos diferentes setores da empresa (corporate), e que, acima de tudo, faça parte da cultura de segurança de voo da organização. CUMPRIDA ANAC AGÊNCIA NACIONAL DE AVIAÇÃO CIVIL 45331 APLICAÇÃO DE COMANDOS DESEMPENHO DO SER HUMANO OPERAÇÃO DA AERONAVE FATOR OPERACIONAL 45331 PRTKB *** AVIÃO AEROSPATIALE AND ALENIA ATR-42-500 AT45 TURBOÉLICE BIMOTOR
## 3: 45331 A-582/CENIPA/2014 - 02 2016-07-29 2016-08-25 2016-12-20 Atuar junto à Administração do Aeroporto Internacional de Guarulhos, de forma que este passe a ministrar treinamento teórico e prático de atendimento às vítimas de acidentes envolvendo os principais tipos de aeronaves que operam naquela localidade, principalmente os das Linhas Aéreas Regulares, com especial ênfase ao “Layout” e aos meios de remoção de passageiros do interior destas aeronaves. CUMPRIDA ANAC AGÊNCIA NACIONAL DE AVIAÇÃO CIVIL 45331 APLICAÇÃO DE COMANDOS DESEMPENHO DO SER HUMANO OPERAÇÃO DA AERONAVE FATOR OPERACIONAL 45331 PRTKB *** AVIÃO AEROSPATIALE AND ALENIA ATR-42-500 AT45 TURBOÉLICE BIMOTOR
## 4: 45331 A-582/CENIPA/2014 - 03 2016-07-29 2016-08-25 NULL Orientar as suas organizações subordinadas em relação ao fiel cumprimento do estabelecido na ICA 100-37, de 28ABR2014, no seu item 5.9.3 e na MCA 100-16, de 18NOV2013, no item 2.3.3. AGUARDANDO RESPOSTA DECEA DEPARTAMENTO DE CONTROLE DE ESPAÇO AÉREO 45331 APLICAÇÃO DE COMANDOS DESEMPENHO DO SER HUMANO OPERAÇÃO DA AERONAVE FATOR OPERACIONAL 45331 PRTKB *** AVIÃO AEROSPATIALE AND ALENIA ATR-42-500 AT45 TURBOÉLICE BIMOTOR
## 5: 45331 A-582/CENIPA/2014 - 01 2016-07-29 2016-08-25 2016-12-20 Atuar junto às empresas que operam segundo o RBAC 121 de forma tal que assegure que o treinamento de Corporate Ressource Management (CRM) esteja adequado a realidade daquela empresa, que seja constantemente avaliado e reforçado (com a participação da alta direção), envolva todos os profissionais da instituição, que garanta a integração dos diferentes setores da empresa (corporate), e que, acima de tudo, faça parte da cultura de segurança de voo da organização. CUMPRIDA ANAC AGÊNCIA NACIONAL DE AVIAÇÃO CIVIL 45331 ATENÇÃO ASPECTO PSICOLÓGICO INDIVIDUAL FATOR HUMANO 45331 PRTKB *** AVIÃO AEROSPATIALE AND ALENIA ATR-42-500 AT45 TURBOÉLICE BIMOTOR
## 6: 45331 A-582/CENIPA/2014 - 02 2016-07-29 2016-08-25 2016-12-20 Atuar junto à Administração do Aeroporto Internacional de Guarulhos, de forma que este passe a ministrar treinamento teórico e prático de atendimento às vítimas de acidentes envolvendo os principais tipos de aeronaves que operam naquela localidade, principalmente os das Linhas Aéreas Regulares, com especial ênfase ao “Layout” e aos meios de remoção de passageiros do interior destas aeronaves. CUMPRIDA ANAC AGÊNCIA NACIONAL DE AVIAÇÃO CIVIL 45331 ATENÇÃO ASPECTO PSICOLÓGICO INDIVIDUAL FATOR HUMANO 45331 PRTKB *** AVIÃO AEROSPATIALE AND ALENIA ATR-42-500 AT45 TURBOÉLICE BIMOTOR
## aeronave_pmd aeronave_pmd_categoria aeronave_assentos aeronave_ano_fabricacao aeronave_pais_fabricante aeronave_pais_registro aeronave_registro_categoria aeronave_registro_segmento aeronave_voo_origem aeronave_voo_destino aeronave_fase_operacao aeronave_tipo_operacao aeronave_nivel_dano aeronave_fatalidades_total codigo_ocorrencia1 ocorrencia_tipo ocorrencia_tipo_categoria taxonomia_tipo_icao codigo_ocorrencia ocorrencia_classificacao ocorrencia_latitude ocorrencia_longitude ocorrencia_cidade ocorrencia_uf ocorrencia_pais ocorrencia_aerodromo ocorrencia_dia ocorrencia_hora investigacao_aeronave_liberada investigacao_status divulgacao_relatorio_numero divulgacao_relatorio_publicado divulgacao_dia_publicacao total_recomendacoes total_aeronaves_envolvidas ocorrencia_saida_pista
## 1: 2495 2495 6 2003 BRASIL BRASIL AVIÃO PARTICULAR FORA DE AERODROMO FORA DE AERODROMO POUSO PRIVADA LEVE 0 52242 ESTOURO DE PNEU FALHA OU MAU FUNCIONAMENTO DE SISTEMA / COMPONENTE | ESTOURO DE PNEU SCF-NP 52242 INCIDENTE PORTO ALEGRE RS BRASIL SBPA 05/01/2012 20:27:00 *** FINALIZADA *** NÃO NULL 0 1 NÃO
## 2: 18600 18600 50 2001 BRASIL BRASIL AVIÃO REGULAR FORA DE AERODROMO FORA DE AERODROMO DESCIDA REGULAR NENHUM 0 45331 COM PESSOAL EM VOO OUTROS | COM PESSOAL EM VOO OTHR 45331 ACIDENTE -23.4355555556 -46.4730555556 GUARULHOS SP BRASIL SBGR 06/01/2012 13:44:00 SIM FINALIZADA A-582/CENIPA/2014 SIM 2016-09-01 3 1 NÃO
## 3: 18600 18600 50 2001 BRASIL BRASIL AVIÃO REGULAR FORA DE AERODROMO FORA DE AERODROMO DESCIDA REGULAR NENHUM 0 45331 COM PESSOAL EM VOO OUTROS | COM PESSOAL EM VOO OTHR 45331 ACIDENTE -23.4355555556 -46.4730555556 GUARULHOS SP BRASIL SBGR 06/01/2012 13:44:00 SIM FINALIZADA A-582/CENIPA/2014 SIM 2016-09-01 3 1 NÃO
## 4: 18600 18600 50 2001 BRASIL BRASIL AVIÃO REGULAR FORA DE AERODROMO FORA DE AERODROMO DESCIDA REGULAR NENHUM 0 45331 COM PESSOAL EM VOO OUTROS | COM PESSOAL EM VOO OTHR 45331 ACIDENTE -23.4355555556 -46.4730555556 GUARULHOS SP BRASIL SBGR 06/01/2012 13:44:00 SIM FINALIZADA A-582/CENIPA/2014 SIM 2016-09-01 3 1 NÃO
## 5: 18600 18600 50 2001 BRASIL BRASIL AVIÃO REGULAR FORA DE AERODROMO FORA DE AERODROMO DESCIDA REGULAR NENHUM 0 45331 COM PESSOAL EM VOO OUTROS | COM PESSOAL EM VOO OTHR 45331 ACIDENTE -23.4355555556 -46.4730555556 GUARULHOS SP BRASIL SBGR 06/01/2012 13:44:00 SIM FINALIZADA A-582/CENIPA/2014 SIM 2016-09-01 3 1 NÃO
## 6: 18600 18600 50 2001 BRASIL BRASIL AVIÃO REGULAR FORA DE AERODROMO FORA DE AERODROMO DESCIDA REGULAR NENHUM 0 45331 COM PESSOAL EM VOO OUTROS | COM PESSOAL EM VOO OTHR 45331 ACIDENTE -23.4355555556 -46.4730555556 GUARULHOS SP BRASIL SBGR 06/01/2012 13:44:00 SIM FINALIZADA A-582/CENIPA/2014 SIM 2016-09-01 3 1 NÃO
E sucesso!
Wheeeew.
Agora que tenho uma tabela com todas as informações que preciso, posso criar algumas visões para tirar alguns insights ou análises interessantes sobre. Claro, após tratarmos alguns pontos dela :)
Tratamento dos Dados
Reordenação das Colunas
Para começar os tratamentos dos dados, reordenarei as colunas para ficar na ordem das bases que foram cruzadas, ou seja, na seguinte ordem:
- ocorrencia;
- ocorrencia_tipo;
- aeronave;
- fator_contribuinte;
- recomendacao;
Lembrando que como as colunas codigo_ocorrencia1, codigo_ocorrencia2, codigo_ocorrencia3, codigo_ocorrencia4 já existiam na tabela “central”, ocorrencia, irei removê-las para evitar algum tipo de mal entendido no vetor.
# Extrai o nome (e a ordem) das colunas pré cruzamento
colunas0 <- names(ocorrencia)
colunas1 <- names(ocorrencia_tipo)[2:length(names(ocorrencia_tipo))] # Eliminando a coluna de codigo_ocorrencia1
colunas2 <- names(aeronave)[2:length(names(aeronave))] # Eliminando a coluna de codigo_ocorrencia2
colunas3 <- names(fator_contribuinte)[2:length(names(fator_contribuinte))] # Eliminando a coluna de codigo_ocorrencia3
colunas4 <- names(recomendacao)[2:length(names(recomendacao))] # Eliminando a coluna de codigo_ocorrencia4
# Concatena os nomes das colunas
ordem_colunas <- c(colunas0, colunas1, colunas2, colunas3, colunas4)
# Atualiza a ordem na tabela por referência
data.table::setcolorder(tabela, ordem_colunas)Conversão das Colunas
Após a ordenação, posso finalmente começar a dar uma olhada na tabela “analítica” (pós-cruzamento das tabelas) carinhosamente chamada de tabela. Vamos dar uma olhadinha:
str(tabela)## Classes 'data.table' and 'data.frame': 12167 obs. of 59 variables:
## $ codigo_ocorrencia : int 52242 45331 45331 45331 45331 45331 45331 45331 45331 45331 ...
## $ codigo_ocorrencia1 : int 52242 45331 45331 45331 45331 45331 45331 45331 45331 45331 ...
## $ codigo_ocorrencia2 : int 52242 45331 45331 45331 45331 45331 45331 45331 45331 45331 ...
## $ codigo_ocorrencia3 : int 52242 45331 45331 45331 45331 45331 45331 45331 45331 45331 ...
## $ codigo_ocorrencia4 : int 52242 45331 45331 45331 45331 45331 45331 45331 45331 45331 ...
## $ ocorrencia_classificacao : chr "INCIDENTE" "ACIDENTE" "ACIDENTE" "ACIDENTE" ...
## $ ocorrencia_latitude : chr "" "-23.4355555556" "-23.4355555556" "-23.4355555556" ...
## $ ocorrencia_longitude : chr "" "-46.4730555556" "-46.4730555556" "-46.4730555556" ...
## $ ocorrencia_cidade : chr "PORTO ALEGRE" "GUARULHOS" "GUARULHOS" "GUARULHOS" ...
## $ ocorrencia_uf : chr "RS" "SP" "SP" "SP" ...
## $ ocorrencia_pais : chr "BRASIL" "BRASIL" "BRASIL" "BRASIL" ...
## $ ocorrencia_aerodromo : chr "SBPA" "SBGR" "SBGR" "SBGR" ...
## $ ocorrencia_dia : chr "05/01/2012" "06/01/2012" "06/01/2012" "06/01/2012" ...
## $ ocorrencia_hora : chr "20:27:00" "13:44:00" "13:44:00" "13:44:00" ...
## $ investigacao_aeronave_liberada : chr "***" "SIM" "SIM" "SIM" ...
## $ investigacao_status : chr "FINALIZADA" "FINALIZADA" "FINALIZADA" "FINALIZADA" ...
## $ divulgacao_relatorio_numero : chr "***" "A-582/CENIPA/2014" "A-582/CENIPA/2014" "A-582/CENIPA/2014" ...
## $ divulgacao_relatorio_publicado : chr "NÃO" "SIM" "SIM" "SIM" ...
## $ divulgacao_dia_publicacao : chr "NULL" "2016-09-01" "2016-09-01" "2016-09-01" ...
## $ total_recomendacoes : int 0 3 3 3 3 3 3 3 3 3 ...
## $ total_aeronaves_envolvidas : int 1 1 1 1 1 1 1 1 1 1 ...
## $ ocorrencia_saida_pista : chr "NÃO" "NÃO" "NÃO" "NÃO" ...
## $ ocorrencia_tipo : chr "ESTOURO DE PNEU" "COM PESSOAL EM VOO" "COM PESSOAL EM VOO" "COM PESSOAL EM VOO" ...
## $ ocorrencia_tipo_categoria : chr "FALHA OU MAU FUNCIONAMENTO DE SISTEMA / COMPONENTE | ESTOURO DE PNEU" "OUTROS | COM PESSOAL EM VOO" "OUTROS | COM PESSOAL EM VOO" "OUTROS | COM PESSOAL EM VOO" ...
## $ taxonomia_tipo_icao : chr "SCF-NP" "OTHR" "OTHR" "OTHR" ...
## $ aeronave_matricula : chr "PRCDL" "PRTKB" "PRTKB" "PRTKB" ...
## $ aeronave_operador_categoria : chr "PARTICULAR" "***" "***" "***" ...
## $ aeronave_tipo_veiculo : chr "AVIÃO" "AVIÃO" "AVIÃO" "AVIÃO" ...
## $ aeronave_fabricante : chr "RAYTHEON AIRCRAFT" "AEROSPATIALE AND ALENIA" "AEROSPATIALE AND ALENIA" "AEROSPATIALE AND ALENIA" ...
## $ aeronave_modelo : chr "58" "ATR-42-500" "ATR-42-500" "ATR-42-500" ...
## $ aeronave_tipo_icao : chr "BE58" "AT45" "AT45" "AT45" ...
## $ aeronave_motor_tipo : chr "PISTÃO" "TURBOÉLICE" "TURBOÉLICE" "TURBOÉLICE" ...
## $ aeronave_motor_quantidade : chr "BIMOTOR" "BIMOTOR" "BIMOTOR" "BIMOTOR" ...
## $ aeronave_pmd : int 2495 18600 18600 18600 18600 18600 18600 18600 18600 18600 ...
## $ aeronave_pmd_categoria : int 2495 18600 18600 18600 18600 18600 18600 18600 18600 18600 ...
## $ aeronave_assentos : chr "6" "50" "50" "50" ...
## $ aeronave_ano_fabricacao : chr "2003" "2001" "2001" "2001" ...
## $ aeronave_pais_fabricante : chr "BRASIL" "BRASIL" "BRASIL" "BRASIL" ...
## $ aeronave_pais_registro : chr "BRASIL" "BRASIL" "BRASIL" "BRASIL" ...
## $ aeronave_registro_categoria : chr "AVIÃO" "AVIÃO" "AVIÃO" "AVIÃO" ...
## $ aeronave_registro_segmento : chr "PARTICULAR" "REGULAR" "REGULAR" "REGULAR" ...
## $ aeronave_voo_origem : chr "FORA DE AERODROMO" "FORA DE AERODROMO" "FORA DE AERODROMO" "FORA DE AERODROMO" ...
## $ aeronave_voo_destino : chr "FORA DE AERODROMO" "FORA DE AERODROMO" "FORA DE AERODROMO" "FORA DE AERODROMO" ...
## $ aeronave_fase_operacao : chr "POUSO" "DESCIDA" "DESCIDA" "DESCIDA" ...
## $ aeronave_tipo_operacao : chr "PRIVADA" "REGULAR" "REGULAR" "REGULAR" ...
## $ aeronave_nivel_dano : chr "LEVE" "NENHUM" "NENHUM" "NENHUM" ...
## $ aeronave_fatalidades_total : int 0 0 0 0 0 0 0 0 0 0 ...
## $ fator_nome : chr NA "APLICAÇÃO DE COMANDOS" "APLICAÇÃO DE COMANDOS" "APLICAÇÃO DE COMANDOS" ...
## $ fator_aspecto : chr NA "DESEMPENHO DO SER HUMANO" "DESEMPENHO DO SER HUMANO" "DESEMPENHO DO SER HUMANO" ...
## $ fator_condicionante : chr NA "OPERAÇÃO DA AERONAVE" "OPERAÇÃO DA AERONAVE" "OPERAÇÃO DA AERONAVE" ...
## $ fator_area : chr NA "FATOR OPERACIONAL" "FATOR OPERACIONAL" "FATOR OPERACIONAL" ...
## $ recomendacao_numero : chr NA "A-582/CENIPA/2014 - 01" "A-582/CENIPA/2014 - 02" "A-582/CENIPA/2014 - 03" ...
## $ recomendacao_dia_assinatura : IDate, format: NA "2016-07-29" "2016-07-29" "2016-07-29" ...
## $ recomendacao_dia_encaminhamento: IDate, format: NA "2016-08-25" "2016-08-25" "2016-08-25" ...
## $ recomendacao_dia_feedback : chr NA "2016-12-20" "2016-12-20" "NULL" ...
## $ recomendacao_conteudo : chr NA "Atuar junto às empresas que operam segundo o RBAC 121 de forma tal que assegure que o treinamento de Corporate "| __truncated__ "Atuar junto à Administração do Aeroporto Internacional de Guarulhos, de forma que este passe a ministrar treina"| __truncated__ "Orientar as suas organizações subordinadas em relação ao fiel cumprimento do estabelecido na ICA 100-37, de 28A"| __truncated__ ...
## $ recomendacao_status : chr NA "CUMPRIDA" "CUMPRIDA" "AGUARDANDO RESPOSTA" ...
## $ recomendacao_destinatario_sigla: chr NA "ANAC" "ANAC" "DECEA" ...
## $ recomendacao_destinatario : chr NA "AGÊNCIA NACIONAL DE AVIAÇÃO CIVIL" "AGÊNCIA NACIONAL DE AVIAÇÃO CIVIL" "DEPARTAMENTO DE CONTROLE DE ESPAÇO AÉREO" ...
## - attr(*, ".internal.selfref")=<externalptr>
Hmm…
Analisando com calma a tabela, podemos anotar alguns pontos estranhos:
- De cara, dá para ver algumas colunas que não eram para ser texto: aeronave_ano_fabricacao, ocorrencia_latitude, ocorrencia_dia, etc;
- Não appenas isso: dentre essas colunas, algumas precisam ser convertidas para número enquanto outras para data;
- Além disso, nossa tabela possui alguns valores estranhos como “***“,”NULL” (literalmente como texto, não como valor booleano), que irei inferir que são Missing já que não possuo metadados sobre o dataset.
Como os valores missing influenciará na conversão dos dados de texto para outros tipos, então começarei tratando eles primeiro.
Corrigindo os valores missing
Para corrigir os valores missing das colunas que são do tipo Texto, primeiro:
Filtramos todas as colunas que são texto;
E depois, caso algum elemento se encaixe em alguns dos valores estranhos que vimos, transformamos em missing (NA). e.g. “***“,”NULL”, etc.
Então, temos:
# Seleciona as colunas que são do tipo character (texto), e guarda na colunas_texto
indices_colunas_texto <- which(unlist(lapply(tabela, is.character)))
colunas_texto <- names(tabela)[indices_colunas_texto]
# Para cada coluna do colunas_texto, troca o valor estranho para missing (NA) usando ifelse
tabela[, (colunas_texto) := lapply(.SD, function(x) ifelse(
x == "***"
| x == "****"
| x == "*****"
| x == "******"
| x == "*******"
| x == "********"
| x == "*********"
| x == "****_***"
| x == "****_****"
| x == "NULL"
| x == "",
NA, x)), .SDcols = colunas_texto]Texto para datas
As colunas que deveriam ser do tipo Data contém “dia” no nome:
names(tabela)[grepl("*dia", names(tabela))]## [1] "ocorrencia_dia" "divulgacao_dia_publicacao" "recomendacao_dia_assinatura" "recomendacao_dia_encaminhamento" "recomendacao_dia_feedback"
de_texto_para_data <- names(tabela)[grepl("*dia", names(tabela))]
str(tabela[, ..de_texto_para_data])## Classes 'data.table' and 'data.frame': 12167 obs. of 5 variables:
## $ ocorrencia_dia : chr "05/01/2012" "06/01/2012" "06/01/2012" "06/01/2012" ...
## $ divulgacao_dia_publicacao : chr NA "2016-09-01" "2016-09-01" "2016-09-01" ...
## $ recomendacao_dia_assinatura : IDate, format: NA "2016-07-29" "2016-07-29" "2016-07-29" ...
## $ recomendacao_dia_encaminhamento: IDate, format: NA "2016-08-25" "2016-08-25" "2016-08-25" ...
## $ recomendacao_dia_feedback : chr NA "2016-12-20" "2016-12-20" NA ...
## - attr(*, ".internal.selfref")=<externalptr>
Logo, para converter, basta aplicarmos o as.IDate - que é essencialmente o Date normal do R, mas compatível com o data.table.
Só um ponto de atenção: a variável ocorrencia_dia não só está como texto quanto também está em um formato de data diferente das demais. Tirando isso, as coisas estão dando tudo certo!
# Converte somente a coluna ocorrencia_dia por ter um formato diferente (DD/MM/YYYY)
tabela[, ocorrencia_dia := as.IDate(ocorrencia_dia, "%d/%m/%Y")]
# Converte colunas que possuem o formato (YYYY-MM-DD)
tabela[, `:=`(
divulgacao_dia_publicacao = as.IDate(divulgacao_dia_publicacao, "%Y-%m-%d"),
recomendacao_dia_assinatura = as.IDate(recomendacao_dia_assinatura, "%Y-%m-%d"),
recomendacao_dia_encaminhamento = as.IDate(recomendacao_dia_encaminhamento, "%Y-%m-%d"),
recomendacao_dia_feedback = as.IDate(recomendacao_dia_feedback, "%Y-%m-%d")
)]
# Converte a coluna ocorrencia_hora para o formato ITime
tabela[, ocorrencia_hora := as.ITime(ocorrencia_hora, "%d/%m/%Y")]Texto para numérico/inteiro
Agora para o caso de ver qual variável deveria ser numérica, não tem jeito. Como o número é pequeno, dá para darmos uma olhada olhando no “str(tabela)” acima.
- ocorrencia_latitude;
- ocorrencia_longitude;
- aeronave_assentos;
- aeronave_ano_fabricacao;
Sabendo quais são as colunas, basta convertê-las:
colunas_texto_para_numero <- c(
"ocorrencia_latitude",
"ocorrencia_longitude",
"aeronave_assentos",
"aeronave_ano_fabricacao"
)
# tabela[, (colunas_texto_para_numero) := lapply(.SD, function(x) as.numeric(x)), .SDcols = colunas_texto_para_numero]Ou pelo menos deveria ser! Tentando converter as 4 colunas de uma vez retorna erro em 2 colunas - que estão aplicando NA por coercion, ou seja, por não saber converter. Olhando mais afundo, notamos que o problema ocorre nas colunas de latitude e longitude. Portanto, vamos converter as outras duas que deram certo, aeronave_assentos e aeronave_assentos, e ver mais a fundo o caso do da latitude e longitude.
tabela[, `:=`(
aeronave_assentos = as.numeric(aeronave_assentos),
aeronave_ano_fabricacao = as.numeric(aeronave_ano_fabricacao)
)]Latitude e Longitude
Texto
Astericos
# Observações que ainda possuem asteriscos
unique(tabela$ocorrencia_latitude)[grepl("\\*", unique(tabela$ocorrencia_latitude))]## [1] "-14.71083***"
# Observações que ainda possuem asteriscos
unique(tabela$ocorrencia_longitude)[grepl("\\*", unique(tabela$ocorrencia_longitude))]## character(0)
Coordenadas em outro sistema (como DMS - Decimal degrees, minutes and seconds)
tabela[ocorrencia_latitude %like% "”", ocorrencia_latitude]## [1] "15° 39’ 00”S" "15° 39’ 00”S"
tabela[ocorrencia_longitude %like% "”", ocorrencia_longitude]## [1] "056° 07’ 03” W" "056° 07’ 03” W"
Outros casos peculiares
head(sort(unique(tabela[, ocorrencia_latitude])), 135)## [1] "- 22.75944" "-0,889722" "-0.0" "-0.0075" "-0.050833333333" "-0.0911111111" "-0.2002777778" "-0.2827778" "-0.41694444444" "-0.8669444444" "-0.985" "-0.9880555556" "-01.43778" "-01.5325" "-03.76472" "-04.1650" "-04.87139" "-05.05972222" "-05.2850" "-05.530555" "-07.04028" "-07.2191666" "-08.12638" "-08.126388" "-08.1263888" "-08.12638888" "-08.12639" "-08.271666" "-08.713611" "-08.84917" "-08.9594444" "-09.53432276" "-09.868888" "-09.96583" "-1,3708" "-1,3808" "-1.0870555555" "-1.144722" "-1.1966666667" "-1.2388888889" "-1.2941666667" "-1.326280" "-1.3611111111" "-1.38000" "-1.3801422" "-1.380277777777" "-1.38472" "-1.3847222222" "-1.384722222222" "-1.38556" "-1.3858333333" "-1.3916666667" "-1.3927777778" "-1.4077777778" "-1.4119444444"
## [56] "-1.415" "-1.41500" "-1.4169444444" "-1.419722222" "-1.4361111111" "-1.437777777777" "-1.4452777778" "-1.46472" "-1.4886111111" "-1.532923792" "-1.5922222222" "-1.6386111111" "-1.65000" "-1.7213888889" "-1.775" "-1.797777777777" "-1.9536111111" "-1.955833" "-1.9813888889" "-10.0061111111" "-10.011389" "-10.017222222" "-10.022222" "-10.058333" "-10.0672222222" "-10.081667" "-10.10806" "-10.182778" "-10.183889" "-10.188187" "-10.29" "-10.2900000" "-10.2916666667" "-10.2961111111" "-10.296389" "-10.3772222222" "-10.4144444444" "-10.418333" "-10.422500" "-10.4908333333" "-10.4933333333" "-10.5261111111" "-10.5305555556" "-10.5972222222" "-10.6002777778" "-10.656111" "-10.7297222222" "-10.7338888889" "-10.7555555556" "-10.7641666667" "-10.7691666667" "-10.804722" "-10.870556" "-10.884167" "-10.8875"
## [111] "-10.8883333333" "-10.9033333333" "-10.927500" "-10.94" "-10.94361" "-10.9583333333" "-10.98472" "-10.9852777778" "-10.991111" "-101.827.777.77" "-102.961.111.11" "-103.452.777.77" "-11.009317" "-11.113611111" "-11.131111" "-11.134167" "-11.2644444444" "-11.383056" "-11.41472222" "-11.4194444444" "-11.42056" "-11.4219444444" "-11.461667" "-11.4955555556" "-11.537666"
head(sort(unique(tabela[, ocorrencia_longitude])), 40)## [1] "- 40.68583" "-0.0" "-18.2250" "-18.83916" "-18.973889" "-20.4230" "-21.24055" "-22.92166666666" "-23.18166666666" "-32.9919444444" "-34.8425" "-34.85" "-34.87833333" "-34.8913888889" "-34.89138889" "-34.9005555556" "-34.91277" "-34.92277" "-34.922777" "-34.92277777" "-34.922777777" "-34.9227777777" "-34.92277777777" "-34.9227777778" "-34.92277778" "-34.92278" "-34.927262" "-34.95027" "-34.9502777778" "-34.9505555555" "-348.425" "-348.452.777.77" "-348.913.888.88" "-349.127.777.77" "-349.227.777.77" "-349.502.777.77" "-35.1758333333" "-35.23" "-35.24341" "-35.29166"
tail(sort(unique(tabela[, ocorrencia_longitude])), 55)## [1] "\\t-55.93888889\\t" "\\t-55.94583333\\t" "\\t-55.97388889\\t" "\\t-56.04083333\\t" "\\t-56.06472222\\t" "\\t-56.08805556\\t" "\\t-56.26361111\\t" "\\t-56.45194444\\t" "\\t-56.46722222\\t" "\\t-56.51388889\\t" "\\t-56.56222222\\t" "\\t-56.62972222\\t" "\\t-56.74527778\\t" "\\t-56.95916667\\t" "\\t-57.043333\\t" "\\t-57.16583333\\t" "\\t-57.26611111\\t" "000" "042.4241" "056° 07’ 03” W" "11.8666666667" "14.98400" "16,6372222" "38.5322222222" "41.06833" "413.077.777.778" "43.98916667" "432.505.555.556" "439.505.555.556" "444.216.666.667" "45.8922222222" "46.473055555556" "46.633888888889" "46.6563888889" "46.9047222222" "46.9436111111" "465.741.666.667" "466.341.666.667" "47.0577777778" "47.9186111111" "48.022222222222" "48.5958333333" "487.575" "488.166.666.667" "49.226667" "49.2286" "49.3988888889"
## [48] "49.4686111111" "493.494.444.444" "55.6725" "56.5230555556" "63.9027777778" "Longitude: -43." "Longitude: -47." "NÃO INFORMADO"
Texto…
Texto 2…
### Caso 1 - Espaço, e.g. "- 22.75944"
tabela[, ocorrencia_latitude := gsub(" ", "", ocorrencia_latitude)]
tabela[, ocorrencia_longitude := gsub(" ", "", ocorrencia_longitude)]
### Caso 2 - Vírgula, e.g. "-0,889722"
tabela[, ocorrencia_latitude := gsub(",", ".", ocorrencia_latitude)]
tabela[, ocorrencia_longitude := gsub(",", ".", ocorrencia_longitude)]
### Caso 3 - Duplo negativo, e.g. "--49.0324242"
tabela[, ocorrencia_latitude := gsub("--", "-", ocorrencia_latitude)]
tabela[, ocorrencia_longitude := gsub("--", "-", ocorrencia_longitude)]
### Caso 4 - Com a palavra Latitude/Longitude na frente, e.g. "Longitude:-47."
tabela[ocorrencia_latitude %like% "Latitude", ocorrencia_latitude := gsub("Latitude:", "", ocorrencia_latitude)]
tabela[ocorrencia_longitude %like% "Longitude", ocorrencia_longitude := gsub("Longitude:", "", ocorrencia_longitude)]
### Caso 5 - Coordenada em DMS - Decimal degrees, minutes and seconds
tabela[ocorrencia_latitude == "15°39’00”S", ocorrencia_latitude := "-15.650000"]
tabela[ocorrencia_longitude == "056°07’03”W", ocorrencia_longitude := "-56.117500"]
### Caso 6 - Asteriscos na frente ou atrás do número (só Lat)
tabela[ocorrencia_latitude == "***-22.98575784", ocorrencia_latitude := "-22.98575784"]
tabela[ocorrencia_latitude == "-14.71083***", ocorrencia_latitude := "-14.71083"]
### Caso 7 - Possui/termina com S, N, W, ou E, mas não está formatado em coordenadas DMS como no Caso 5
tabela[, ocorrencia_latitude := gsub("S", "", ocorrencia_latitude)]
tabela[, ocorrencia_latitude := gsub("N", "", ocorrencia_latitude)]
tabela[, ocorrencia_longitude := gsub("W", "", ocorrencia_longitude)]
tabela[, ocorrencia_longitude := gsub("E", "", ocorrencia_longitude)]
### Caso 8 - Possui/termina com o símbolo de Grau ("º"/"°")
tabela[, ocorrencia_latitude := gsub("°", "", ocorrencia_latitude)]
tabela[, ocorrencia_longitude := gsub("°", "", ocorrencia_longitude)]
tabela_ <- data.table::copy(tabela)
### Caso 9 - Número cheio de separadores usando ponto ("."). (Lat e Log)
# Cria flag marcando casos que possíveis não estão todos corretos
tabela[, flag_lat_long := fifelse(
lengths(regmatches(ocorrencia_latitude, gregexpr("\\.", ocorrencia_latitude))) > 1
| lengths(regmatches(ocorrencia_longitude, gregexpr("\\.", ocorrencia_longitude))) > 1,
FALSE,
TRUE
)
]
# Latitude
tabela[
lengths(regmatches(ocorrencia_latitude, gregexpr("\\.", ocorrencia_latitude))) > 1,
ocorrencia_latitude := fifelse(
as.numeric(gsub("\\.", "", ocorrencia_latitude)) > 0,
sub("(.{2})(.*)", "\\1.\\2", gsub("\\.", "", ocorrencia_latitude)),
sub("(.{3})(.*)", "\\1.\\2", gsub("\\.", "", ocorrencia_latitude))
)
]
# Longitude
tabela[
lengths(regmatches(ocorrencia_longitude, gregexpr("\\.", ocorrencia_longitude))) > 1,
ocorrencia_longitude := fifelse(
as.numeric(gsub("\\.", "", ocorrencia_longitude)) > 0,
sub("(.{2})(.*)", "\\1.\\2", gsub("\\.", "", ocorrencia_longitude)),
sub("(.{3})(.*)", "\\1.\\2", gsub("\\.", "", ocorrencia_longitude))
)
]
### Após tratamentos, FINALMENTE converte as colunas para numérico
tabela[, `:=`(
ocorrencia_latitude = as.numeric(ocorrencia_latitude),
ocorrencia_longitude = as.numeric(ocorrencia_longitude)
)]## Warning in eval(jsub, SDenv, parent.frame()): NAs introduzidos por coerção
## Warning in eval(jsub, SDenv, parent.frame()): NAs introduzidos por coerção
### Caso 10 - 44993 e 50794 não possuem longitude
# Como a ocorrencia 44993 foi na cidade do Rio de Janeiro, aproxima usando as coordenadas
# do Aeroporto Doméstico Santos Dumont: -22.90825417333246, -43.16789880589976
tabela[codigo_ocorrencia == 44993, ocorrencia_longitude := -43.16789880589976]
# Como a ocorrencia 50794 foi na cidade de Turmalina, MG, aproxima usando as coordenadas
# do ponto zero da cidade: -17.285824901708047, -42.731887838264434
tabela[codigo_ocorrencia == 50794, ocorrencia_longitude := -42.731887838264434]Após tratamentos:
head(sort(unique(tabela[, ocorrencia_latitude])), 135)## [1] -235.07500 -229.87500 -229.27500 -228.22500 -222.97500 -204.42500 -204.37500 -173.82500 -167.02500 -163.62500 -158.62500 -158.52500 -156.52500 -98.68889 -95.87500 -95.17222 -93.67500 -92.56111 -92.28333 -90.33333 -89.59444 -87.13611 -85.90556 -85.66667 -81.26389 -81.16944 -80.38333 -78.44444 -78.21389 -75.99444 -75.02500 -73.98400 -73.58333 -72.29167 -71.60556 -71.48333 -70.91944 -70.89444 -70.46389 -68.23611 -68.18889 -67.63889 -67.63056 -66.93056 -65.40278 -65.29167 -60.86944 -59.08611 -58.68333 -53.68056 -52.48805 -51.46111 -50.50556 -49.21167 -48.74444 -48.71389 -48.48056 -48.10056 -47.20278 -46.94361 -45.19050 -44.95722 -42.50556 -42.44444 -42.06750 -41.62500 -40.33250 -37.75833 -37.08333 -35.09167 -34.97941 -33.43639 -33.10528 -32.41556 -32.22194 -31.45139 -31.42278 -31.05167 -30.73056 -30.72778 -30.60556 -30.44944 -30.41111 -30.38889 -30.38333 -30.36083 -30.24556 -30.05028 -29.99472 -29.99472
## [91] -29.99472 -29.99389 -29.99389 -29.99389 -29.99389 -29.99388 -29.99194 -29.98806 -29.69583 -29.41306 -29.36472 -29.19556 -29.04444 -28.95972 -28.93056 -28.87431 -28.48668 -27.90361 -27.79167 -27.78139 -27.67274 -27.67253 -27.67028 -27.67028 -27.67028 -27.67028 -27.61028 -27.56667 -27.17111 -27.16333 -27.16306 -27.13389 -27.08722 -27.05750 -27.01500 -26.87861 -26.87861 -26.83278 -26.78250 -26.66667 -26.65528 -26.55805 -26.22306 -26.22306 -26.05889
head(sort(unique(tabela[, ocorrencia_longitude])), 40)## [1] -6.013827e+10 -4.819457e+08 -6.689750e+02 -6.006250e+02 -5.633750e+02 -5.611750e+02 -5.589250e+02 -5.215750e+02 -4.599750e+02 -4.583750e+02 -4.502250e+02 -4.501250e+02 -4.316250e+02 -3.832250e+02 -3.484250e+02 -7.277972e+01 -7.277972e+01 -7.277972e+01 -7.276944e+01 -7.276944e+01 -7.274528e+01 -7.270556e+01 -7.194694e+01 -7.168833e+01 -7.168833e+01 -7.164860e+01 -7.048278e+01 -7.048278e+01 -7.015194e+01 -7.011417e+01 -7.009389e+01 -7.002528e+01 -6.993778e+01 -6.993778e+01 -6.991694e+01 -6.982333e+01 -6.978000e+01 -6.957167e+01 -6.942361e+01 -6.926639e+01
tail(sort(unique(tabela[, ocorrencia_longitude])), 40)## [1] -18.973889 -18.839160 -18.225000 -8.008720 -6.184667 -5.060556 0.000000 11.866667 14.984000 16.637222 38.532222 41.068330 41.307778 42.424100 43.250556 43.950556 43.989167 44.421667 45.892222 46.473056 46.574167 46.633889 46.634167 46.656389 46.904722 46.943611 47.057778 47.918611 48.022222 48.595833 48.816667 49.226667 49.228600 49.349444 49.398889 49.468611 55.672500 56.523056 63.902778 487.575000
Após tratamentos…
Análises
Em construção, maybe
Ocorrências
# Seleciona as colunas relevantes, e dá um distinct para evitar observações duplicadas
ocorrencias_tempo <- unique(tabela[, .(ocorrencia_dia, codigo_ocorrencia, ocorrencia_classificacao)])
#
ocorrencias_tempo[, `:=`(
ocorrencia_ano = as.character(data.table::year(ocorrencia_dia)),
ocorrencia_mes = paste0(substr(ocorrencia_dia, 1, 7), "-01"),
ocorrencia_dia_plot = as.character(ocorrencia_dia),
ocorrencia_dia_calendario = as.IDate(substr(ocorrencia_dia, 6, 10), format="%m-%d")
)]Número de ocorrências pelo tempo
Ano e Mês
e_ocorrencias_ano <- ocorrencias_tempo[, .(Ocorrências = .N), keyby = ocorrencia_ano] |>
e_charts(ocorrencia_ano, height = 300, elementId = "e_ocorrencias_ano") |>
e_title("Número de Ocorrências Aeronaúticas - Ao Ano", left = "center") |>
e_legend(bottom = 0) |>
e_theme("chalk") |>
e_line(Ocorrências, name = "Número de Ocorrências") |>
e_mark_line("Número de Ocorrências", data = list(type = "average")) |>
e_tooltip(trigger = "axis") |>
e_labels() |>
e_datazoom(show = FALSE)
e_ocorrencias_mes <- ocorrencias_tempo[, .(Ocorrências = .N), keyby = ocorrencia_mes] |>
e_charts(ocorrencia_mes, height = 300, elementId = "e_ocorrencias_mes") |>
e_title("Número de Ocorrências Aeronaúticas - Ao Mês", left = "center") |>
e_legend(show = FALSE) |>
e_theme("chalk") |>
e_line(Ocorrências, name = "Número de Ocorrências") |>
e_mark_line("Número de Ocorrências", data = list(type = "average")) |>
e_tooltip(trigger = "axis") |>
e_datazoom() |>
e_connect("e_ocorrencias_ano")
e_arrange(e_ocorrencias_ano, e_ocorrencias_mes)Ano e Mês - Por classificação de ocorrência
e_ocorrencias_classif_ano <- ocorrencias_tempo[, .(Ocorrências = .N), keyby = c("ocorrencia_ano", "ocorrencia_classificacao")] |>
group_by(ocorrencia_classificacao) |>
e_charts(ocorrencia_ano, height = 300, elementId = "e_ocorrencias_classif_ano") |>
e_title("Número de Ocorrências Aeronaúticas - Ao Ano", left = "center") |>
e_legend(bottom = 0) |>
e_theme("chalk") |>
e_line(Ocorrências) |>
e_mark_line("Número de Ocorrências", data = list(type = "average")) |>
e_tooltip(trigger = "axis") |>
e_labels() |>
e_datazoom(show = FALSE)
e_ocorrencias_classif_mes <- ocorrencias_tempo[, .(Ocorrências = .N), keyby = c("ocorrencia_mes", "ocorrencia_classificacao")] |>
group_by(ocorrencia_classificacao) |>
e_charts(ocorrencia_mes, height = 300, elementId = "e_ocorrencias_classif_mês") |>
e_title("Número de Ocorrências Aeronaúticas - Ao Mês", left = "center") |>
e_legend(show = FALSE) |>
e_theme("chalk") |>
e_line(Ocorrências) |>
e_mark_line("Número de Ocorrências", data = list(type = "average")) |>
e_tooltip(trigger = "axis") |>
e_datazoom() |>
e_connect("e_ocorrencias_classif_ano")
e_arrange(e_ocorrencias_classif_ano, e_ocorrencias_classif_mes)Dia - Calendário
ocorrencias_tempo_dia <- ocorrencias_tempo[, .(N = .N), keyby = ocorrencia_dia_calendario]
ano_tbl_ocorrencias <- year(
ocorrencias_tempo_dia[!is.na(ocorrencia_dia_calendario)][1, ocorrencia_dia_calendario]
)
min_ocorrencias_dia <- min(ocorrencias_tempo_dia[!is.na(ocorrencia_dia_calendario), N])
max_ocorrencias_dia <- max(ocorrencias_tempo_dia[!is.na(ocorrencia_dia_calendario), N])
ocorrencias_tempo_dia |>
e_charts(ocorrencia_dia_calendario)|>
e_title("Número de Ocorrências Aeronaúticas - Sumarizado por Dia", top = "1%", left = "center") |>
e_theme("essos") |>
e_calendar(
range = ano_tbl_ocorrencias,
# orient = "vertical",
# width = 1,
cellSize = 12.5,
left = "center",
top = "15%",
# dayLabel = list(show = F),
yearLabel = list(show = F)
) |>
e_heatmap(N, coord_system = "calendar") |>
e_visual_map(
min = min_ocorrencias_dia,
max = max_ocorrencias_dia,
type = "piecewise",
orient = "horizontal",
left = "center",
top = "6.75%"
) |>
e_tooltip(formatter = htmlwidgets::JS("
function(params){
return('<strong>Data: </strong>' + params.value[0] + '<br /><strong>Número de Ocorrências: </strong>' + params.value[1])
}
")
)Ocorrências pelo tipo
ocorrencias_tipo_plot <- tabela[, .N, keyby = c("ocorrencia_tipo", "ocorrencia_classificacao")]Top 10 - Ocorrências por Tipo
tail(ocorrencias_tipo_plot[order(N)], 10) |>
group_by(ocorrencia_classificacao) |>
e_charts(ocorrencia_tipo) |>
e_title("Top 10 - Ocorrências por Tipo", left = "center") |>
e_theme("chalk") |>
e_x_axis(axisLabel = list(fontSize = 7)) |>
e_legend(bottom = 0) |>
e_bar(N, emphasis = list(focus = "self")) |>
e_tooltip() |>
e_flip_coords()Top 10 - Ocorrências por Tipo - Incidente Grave
tail(ocorrencias_tipo_plot[ocorrencia_classificacao == "INCIDENTE GRAVE"][order(N)], 10) |>
e_charts(ocorrencia_tipo) |>
e_title("Top 10 - Ocorrências por Tipo - Incidente Grave", left = "center") |>
e_x_axis(axisLabel = list(fontSize = 7)) |>
e_theme("chalk") |>
e_legend(bottom = 0) |>
e_bar(N, colorBy = "data", emphasis = list(focus = "self")) |>
e_tooltip() |>
e_flip_coords()Mapa das Ocorrências
Em construção
Recomendações
Em construção